<!--
 * @Author: liaoxing
 * @Date: 2021-11-24 15:07:53
 * @LastEditors: liaoxing
 * @LastEditTime: 2021-12-20 09:46:59
 * @Description: liaoxing created
 * @FilePath: \品新集成管理系统\pin-xin-admin\src\views\report\task.vue
-->
<template>
  <div class="timingTask">
    <div class="headerBox">
      <el-button type="primary" size="small" @click="createTask">创建任务</el-button>
      <div class="flex fr taskSearchBox">
        <el-input v-model="searchValue" placeholder="请输入报表名称"></el-input>
        <el-button type="primary" size="small" @click="queryTask('init')">搜 索</el-button>
      </div>
    </div>
    <div class="contentBox">
      <el-table
        v-loading="loading2"
        :data="taskList"
        border
        stripe
        style="width: 100%">
        <el-table-column
          prop="reportName"
          label="报表"
          width="200">
        </el-table-column>
        <el-table-column
          prop="triggerCron"
          label="任务调度"
          width="250">
        </el-table-column>
        <el-table-column
          prop="receiver"
          label="接收人">
          <template slot-scope="scope">
            <el-popover
              placement="top-start"
              width="300"
              trigger="hover"
              >
              <!-- :content="JSON.stringify(scope.row.receiver)" -->
              <!-- <el-button slot="reference">hover 激活</el-button> -->
              <code style="white-space: pre-line">
                {{ scope.row.name.join(',') }}
              </code>
              <span slot="reference" class="more">{{ scope.row.name.join(',') }}</span>
            </el-popover>
          </template>
        </el-table-column>
        <el-table-column
          prop="status"
          label="状态"
          width="80">
          <template slot-scope="scope">
            <span>{{ scope.row.status ? "开启" : "关闭"}}</span>
          </template>
        </el-table-column>
        <el-table-column
          prop="queryParams"
          label="参数">
          <template slot-scope="scope">
            <el-popover
              placement="top-start"
              width="600"
              trigger="hover">
              <!-- :content="JSON.stringify(scope.row.queryParams)" -->
              <!-- <el-button slot="reference">hover 激活</el-button> -->
              <code style="white-space: pre-wrap">
                {{ JSON.stringify(scope.row.jobData.queryParams, null, 2) }}
              </code>
              <span slot="reference" class="more">{{ JSON.stringify(scope.row.jobData.queryParams) }}</span>
            </el-popover>
          </template>
        </el-table-column>
        <el-table-column
          prop="description"
          label="描述"
          width="400">
          <template slot-scope="scope">
            <el-popover
              placement="top-start"
              width="500"
              trigger="hover"
              :content="scope.row.description">
              <span slot="reference" class="more">{{ scope.row.description }}</span>
            </el-popover>
          </template>
        </el-table-column>
        <el-table-column
          prop="execTime"
          label="最后执行时间"
          width="200">
        </el-table-column>
        <el-table-column
          prop="execCOde"
          label="执行状态"
          width="100">
          <template slot-scope="scope">
            <span>{{ scope.row.execCode === null ? "未执行" : scope.row.execCode ? "成功" : "失败"}}</span>
          </template>
        </el-table-column>
        <el-table-column
          label="操作"
          width="110">
          <template slot-scope="scope">
            <el-tooltip content="修改任务" placement="top" effect="dark">
              <span class="jstarfont jstar-mulu finger" @click="editTask(scope.row)"></span>
            </el-tooltip>
            <el-tooltip :content="scope.row.status ? '关闭' : '启用'" placement="top" effect="dark">
              <span class="jstarfont finger" :class="{'jstar-guanbi': scope.row.status, 'jstar-kaiqi' : !scope.row.status, 'color-red': scope.row.status }" @click="editStatus(scope.row)"></span>
            </el-tooltip>
            <el-tooltip content="删除" placement="top" effect="dark">
              <span class="jstarfont jstar-shanchutianchong finger" @click="deleteTask(scope.row.id, scope.row.status)"></span>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        style="float: right; margin-top: 20px"
        :current-page="pageNum"
        :page-size="pageSize"
        layout="total, prev, pager, next, jumper"
        :total="totalSize">
      </el-pagination>
    </div>
    <el-dialog :title="isEdit ? '修改任务' : '创建任务'" :visible.sync="dialogFormVisible" width="70%" top="5vh" :close-on-click-modal="false">
      <div class="flex">
        <div class="formBox">
          <el-form :model="chooseData" label-width="100" :rules="rules" ref="taskForm">
            <el-form-item label="选择报表" prop="bizId">
              <!-- <el-input v-model="chooseData.bizId"></el-input> -->
              <div class="chooseBox" @click="openChooseTree()" @mouseleave="openChooseExtendsBox = false">
                <span style="display: none">{{ chooseData.bizId }}</span>
                <span>{{ chooseData.reportName || reportName}}</span>
                <div class="chooseExtendsBox" v-if="openChooseExtendsBox">
                  <el-input
                    placeholder="输入关键字进行过滤"
                    v-model="filterText">
                  </el-input>
                  <div class="elTreeBox">
                    <el-tree
                      v-loading="loading"
                      :data="dataList"
                      :props="defaultProps"
                      node-key="id"
                      show-checkbox
                      @check-change="handleNodeClick"
                      :filter-node-method="filterNode"
                      :highlight-current="true"
                      ref="taskTree"
                      default-expand-all
                    >
                    </el-tree>
                  </div>
                </div>
              </div>
            </el-form-item>
            <el-form-item label="接收人" prop="receiver">
              <div class="chooseBox" @click="openEmailTree()" @mouseleave="openEmailSelect = false">
                <span style="display: none">{{ chooseData.receiver }}</span>
                <el-tooltip :content="receiverName" placement="top" effect="dark">
                  <span class="more">{{ receiverName }}</span>
                </el-tooltip>
                <div class="chooseExtendsBox" v-show="openEmailSelect">
                  <el-input
                    placeholder="输入关键字进行过滤"
                    v-model="filterText2">
                  </el-input>
                  <div class="elTreeBox">
                    <el-tree
                      v-loading="loading"
                      :data="personList"
                      :props="defaultProps2"
                      node-key="id"
                      show-checkbox
                      @check-change="handleNodeClick2"
                      :filter-node-method="filterNode2"
                      :highlight-current="true"
                      ref="taskTree2"
                      default-expand-all
                    >
                    </el-tree>
                  </div>
                </div>
              </div>
              <!-- <el-input v-model="chooseData.receiver"></el-input> -->
              <!-- <el-input type="textarea" :rows="3" v-model="chooseData.receiver"></el-input> -->
            </el-form-item>
            <el-form-item label="任务调度" prop="triggerCron">
              <el-input v-model="chooseData.triggerCron"></el-input>
            </el-form-item>
            <!-- <el-form-item label="心跳">
              <el-input v-model="chooseData.heartbeat"></el-input>
            </el-form-item> -->
            <el-form-item label="参数 （请使用json字符串格式）" prop="queryParams">
              <el-input type="textarea" :rows="6" v-model="chooseData.queryParams"></el-input>
            </el-form-item>
            <!-- <el-form-item label="结束时间" :prop="'queryParams.endDate'">
              <el-input v-model="chooseData.queryParams.endDate"></el-input>
            </el-form-item> -->
            <el-form-item label="描述" >
              <el-input type="textarea" :rows="3" v-model="chooseData.description"></el-input>
            </el-form-item>
          </el-form>
          <div slot="footer" class="dialog-footer">
            <el-button type="primary" @click="submitForm">确 定</el-button>
          </div>
        </div>
        <div class="tipsBox">
          <h2>参考文档</h2>
          <h3>任务调度-cron</h3>
          <p v-for="(item, index) in cronList" :key="'cronList' + index">
            {{ item }}
          </p>
          <h3>参数</h3>
          <p>
            请使用json字符串格式<br><br>
            {<br>
              &nbsp;&nbsp;"endDate":;&nbsp;"",<br>
              &nbsp;&nbsp;"startDate";&nbsp;:""<br>
              &nbsp;&nbsp;"key":;&nbsp;"value"<br>
            }
          </p>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
// import  { isValidCron } from 'cron-validator'
import cronList from "@/constant/tipsList"
import { validator } from "@/utils/vali"
export default {
  name: "timingTask",
  data () {
    let checkMail = async (rule, value, callback) => {
      if (!value) {
        return callback(new Error('接收人邮箱不能为空！'))
      }
      let emailList = value.split(',')
      for (let item of emailList) {
        let flag = validator.email.test(item.trim())
        if (!flag) {
          return callback(new Error(item + ' 格式错误！'))
        }
      }
      callback()
    }
    let checkCron = async (rule, value, callback) => {
      if (!value) {
        return callback(new Error('cron表达式不能为空！'))
      }
      // if (!isValidCron(value)) {
      //   return callback(new Error('cron表达式错误！'))
      // }
      callback()
    }
    let checkParams = async (rule, value, callback) => {
      if (!value) {
        return callback(new Error('参数不能为空！'))
      }
      try{
        JSON.parse(value)
        callback()
      }catch(e){
        return callback(new Error('参数格式错误！'))
      }
      
    }
    return {
      pageLoading: false,
      taskList: [],
      isEdit: false,
      dialogFormVisible: false,
      chooseData: {
        "bizId": "",
        "receiver": "",
        "triggerCron": "",
        "queryParams": ''
      },
      openChooseExtendsBox: false,
      filterText: '',
      filterText2: '',
      loading: false,
      dataList: [],
      defaultProps: {
        children: 'children',
        label: 'name',
        disabled: (data) => { 
          if (data.children) {
            return true
          }
          return false
        }
      },
      defaultProps2: {
        children: 'children',
        label: 'username'
      },
      reportName: '',
      rules: {
        bizId: [
          { required: true, message: '请选择报表', trigger: 'blur' },
        ],
        receiver: [
          { required: true, message: '请选择接收人', trigger: 'change' },
        ],
        triggerCron: [
          { required: true, validator: checkCron, trigger: 'blur' },
        ],
        queryParams: [
          { required: true, validator: checkParams, trigger: 'blur' }
        ]
      },
      cronList: null,
      changeStatus: false,
      pageSize: 14,
      pageNum: 1,
      searchValue: '',
      totalSize: 0,
      loading2: false,
      openEmailSelect: false,
      personList: null,
      choosePerson: [],
      receiverName: ''
    }
  },
  watch: {
    filterText(val) {
      this.$refs.taskTree.filter(val);
    },
    filterText2(val) {
      this.$refs.taskTree2.filter(val);
    },
    pageNum: {
      deep: true,
      handler: function () {
        this.queryTask()
      }
    }
  },
  computed: {
    queryParamsStr: function () {
      return JSON.stringify(this.chooseData.queryParams)
    }
  },
  async created () {
    this.cronList = cronList
    await this.queryTask()
    await this.queryUserForEmail()
  },
  methods: {
    /* createTask */
    createTask () {
      this.dialogFormVisible = true
      this.changeStatus = false
      if (this.isEdit) {
        this.isEdit = false
        this.reportName = ''
        this.receiverName = ''
        this.choosePerson = []
        this.chooseData = {
          "bizId": "",
          "receiver": "",
          "triggerCron": "",
          "queryParams": ''
        }
      }
    },
    /* 查询报表 */
    queryTask (initPage) {
      this.loading2 = true
      if (initPage == 'init') {
        this.pageNum = 1
      }
      let params = {
        pn: this.pageNum,
        ps: this.pageSize,
        reportName: this.searchValue
      }
      this.searchValue || delete params.reportName
      this.$report.queryTask(params)
        .then(res => {
          if (res.code === 200) {
            this.taskList = res.data.rows
            this.totalSize = res.data.total * 1
          }else {
            this.$message.error(res.code + '-' + res.msg)
          }
          this.loading2 = false
        })
        .catch(e => {
          this.$message.error(e.toString())
        })
    },
    /* 打开选择报表树 */
    openChooseTree () {
      this.openChooseExtendsBox = true
      this.queryPersonReport()
    },
    /* 打开邮箱地址选择树 */
    openEmailTree () {
      this.openEmailSelect = true
      // this.receiverName = ''
      // this.choosePerson = []
      // if (this.chooseData.receiver) {
      //   this.$nextTick(() => {
      //     this.$refs.taskTree2.setCheckedKeys(this.chooseData.receiver.split(','))
      //   })
      // }
      
    },
    /* 报表树选择 */
    handleNodeClick(item, checked) {
      if(checked === true) {
        this.chooseData.bizId = item.id
        this.reportName = item.name
        this.chooseData.reportName && (this.chooseData.reportName = item.name)
        this.$refs.taskTree.setCheckedKeys([item.id])
        this.$report.queryParams(item.id)
          .then(res => {
          if (res.code === 200) {
            this.chooseData.queryParams = JSON.stringify(res.data, null, 2)
          }else {
            this.$message.error(res.code + '-' + res.msg)
          }
          this.loading = false
        })
        .catch(e => {
          this.$message.error(e.toString())
        })
      } else {
        if (this.chooseData.bizId == item.id) {
          this.$refs.taskTree.setCheckedKeys([item.id])
        }
      }
      
    },
    /* 邮箱树选择 */
    handleNodeClick2 (item, checked) {
      if (checked) {
        this.choosePerson.push(item)
      } else {
        let index = this.choosePerson.findIndex(i => i.id === item.id)
        this.choosePerson.splice(index, 1)
      }
      let nameArr = []
      let idArr = []
      this.choosePerson.forEach(element => {
        nameArr.push(element.username)
        idArr.push(element.id)
      })
      
      this.chooseData.receiver = idArr.join(',')
      this.receiverName = nameArr.join(',')
      console.log(this.chooseData)
    },
    /* 查询用户 */
    queryUserForEmail () {
      this.loading = true
      this.$report.userList()
        .then(res => {
          if (res.code === 200) {
            let hasEmailArr = res.data.filter(item => (item.email != null && item.email))
            this.personList = hasEmailArr
          } else {
            this.$message.error(res.code + '-' + res.msg)
          }
          this.loading = false
        })
        .catch(e => {
          this.$message.error(e.toString())
        })
    },
    /* 报表树过滤 */
    filterNode(value, data) {
      if (!value) return true;
      return data.name.indexOf(value) !== -1;
    },
    /* 报表树过滤 */
    filterNode2(value, data) {
      if (!value) return true;
      return data.username.indexOf(value) !== -1;
    },
    /* 回显报表树 */
    reviewChooseNode () {
      this.$refs.taskTree.setCheckedKeys([this.chooseData.bizId])
    },
    /* 查询个人报表 */
    queryPersonReport () {
      this.loading = true
      this.$report.userReport()
        .then(res => {
          if (res.code === 200) {
            this.dataList = res.data
            this.$nextTick(() => {
              this.reviewChooseNode()
            })
          }else {
            this.$message.error(res.code + '-' + res.msg)
          }
          this.loading = false
        })
        .catch(e => {
          this.$message.error(e.toString())
        })
    },
    /* 提交表单 */
    submitForm () {
      this.$refs.taskForm.validate((valid) => {
        if (valid) {
          this.submit()
        } else {
          console.log('error submit!!');
          return false;
        }
      })
    },
    /* 提交函数 */
    submit () {
      let baseParams = JSON.parse(JSON.stringify(this.chooseData))
      /* 修改提交结构 */
      baseParams.bizName = "report.email"
      baseParams.jobData = {
        queryParams: JSON.parse(this.chooseData.queryParams),
        receiver: this.chooseData.receiver
      }
      delete baseParams.receiver
      delete baseParams.queryParams
      // baseParams.queryParams = JSON.parse(this.chooseData.queryParams)
      let params
      let httpApi = 'addTask'
      if (!this.isEdit) {
        baseParams.status = 0
        params = baseParams
      } else {
        baseParams.action = this.changeStatus ? "status" : "info"
        params = {
          id: baseParams.id,
          params: baseParams
        }
        httpApi = 'editTask'
      }
      this.loading2 = true
      this.$report[httpApi](params)
        .then(res => {
          if (res.code === 200) {
            this.$message.success("提交成功！")
            this.dialogFormVisible = false
            this.queryTask(this.isEdit ? '' : 'init')
          }else {
            this.$message.error(res.code + '-' + res.msg)
          }
          this.loading2 = false
        })
        .catch(e => {
          console.log(e.toString(), 111)
          this.$message.error(e.toString())
        })
    },
    /* 删除任务 */
    deleteTask (id, status) {
      if (status) {
        this.$message.warning("请先关闭该任务，才能删除！")
        return
      }
      this.$confirm('此操作将删除该任务, 是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          this.$report.deleteTask(id)
          .then(res => {
            if (res.code === 200) {
              this.queryTask('init')
            }else {
              this.$message.error(res.code + '-' + res.msg)
            }
            this.loading = false
          })
          .catch(e => {

            this.$message.error(e.toString())
          })
        }).catch(() => {         
      })
    },
    /* 修改任务 */
    editTask (item) {
      this.isEdit = true
      this.changeStatus = false
      let para = JSON.parse(JSON.stringify(item))
      para.queryParams = JSON.stringify(item.jobData.queryParams, null, 2)
      para.receiver = item.jobData.receiver
      delete para.jobData
      this.chooseData = para
      this.dialogFormVisible = true
      this.$nextTick(() => {
        this.$refs.taskTree2.setCheckedKeys(para.receiver.split(','))
      })
    },
    /* 修改状态 */
    editStatus (item) {
      this.isEdit = true
      this.changeStatus = true
      let para = JSON.parse(JSON.stringify(item))
      para.queryParams = JSON.stringify(item.jobData.queryParams)
      para.receiver = item.jobData.receiver
      delete para.jobData
      para.status = item.status ? 0 : 1
      this.chooseData = para
      this.submit()
    }
  }
}
</script>

<style lang="less">
.timingTask{
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  padding: 16px;
  .el-input{
    textarea{
      white-space: pre-line
    }
  }
  .el-checkbox__input.is-disabled .el-checkbox__inner{
    display: none;
  }
  .el-tree-node__content{
    height: 40px;
    line-height: 40px;
    font-size: 13px;
}
  .formBox{
    height: 100%;
    width: 50%;
  }
  .tipsBox{
    width: 50%;
    height: 700px;
    padding: 0 0 0 40px;
    box-sizing: border-box;
    overflow: auto;
  }
  .headerBox{
    height: 66px;
    margin-bottom: 10px;
    background-color: white;
    display: flex;
    align-items: center;
    padding: 0 10px;
    position: relative;
    .taskSearchBox{
      height: 40px;
      align-items: center;
      position: absolute;
      right: 10px;
      .el-input{
        margin-bottom: 0;
        margin: 0 10px;
      }
    }
  }
  .contentBox{
    height: calc(100% - 76px);
    background-color: white;
  }
  .chooseBox{
    position: relative;
    font-size: 14px;
    display: inline-block;
    width: 100%;
    height: 40px;
    line-height: 40px;
    border: 1px solid #DCDFE6;
    border-radius: 4px;
    box-sizing: border-box;
    padding: 0 15px;
    .chooseExtendsBox{
      height: 300px;
      width: 100%;
      position: absolute;
      top: 38px;
      left: 0;
      border-radius: 4px;
      background-color: white;
      box-shadow: 0 0 2px 1px rgb(194, 194, 194);
      z-index: 99;
      box-sizing: border-box;
      padding: 20px;
      .elTreeBox{
        overflow: auto;
        height: 220px;
      }
    }
  }
  .jstarfont {
    margin: 0 5px;
  }
}
</style>